#include<iostream>
#include<stdlib.h>
#include"medialib.h"
#include<glob.h>
#include<syslog.h>
#include<proto.h>
#include<unistd.h>
#include "mytbf.h"
#include"server_config.h"
#include<sys/types.h>
#include<sys/stat.h>
#include<cstring>
#include<fcntl.h>
#include<errno.h>
#include<stdio.h>

#define MAX_PATH 50
 
extern server_cfg_st server_cfg;
#define LINEBUFSIZE 1024
#define MP3_BITRATE 64*1024 //correct bps:128*1024

// 关于每个频道最详细的信息
struct channel_context_st{
    channid_t channid; // 频道id
    char * desc; // 频道的描述信息
    glob_t mp3glob; // 通过glob列出信息，所以这个时记录这个文件路径的信息
    int pos; 
    int fd; // 文件描述符
    off_t offset; // 记录文件读取到哪里了
    mytbf_t *tbf;  // 流量控制
};


static channel_context_st channel_context[CHANNERNO+1];

static struct channel_context_st *path2entity(const char* path) // ****
{
    // path/desc.text  path/*.mp3
    syslog(LOG_INFO, "current path :%s\n", path);
    char pathstr[MAX_PATH] = {'\0'};
    char linebuf[LINEBUFSIZE];
    FILE *fp;
    struct channel_context_st *me;
    static channid_t curr_id = MINCHANNID;
    strcat(pathstr, path);
    strcat(pathstr, "/desc.txt");
    fp = fopen(pathstr, "r");
    syslog(LOG_INFO, "channel dir:%s\n", pathstr);
    if(fp == NULL)
    {
        syslog(LOG_INFO, "%s is not a channel dir(can't find desc.txt)", path);
        return NULL;
    }
    if(fgets(linebuf, LINEBUFSIZE, fp) == NULL) // 写的不好，只能读一行desc
    {
        syslog(LOG_INFO, "%s is not a channel dir(cant get the desc.text)", path);
        fclose(fp);
        return NULL;
    }
    fclose(fp);
    me = (channel_context_st*)malloc(sizeof(channel_context_st));
    if(me == NULL)
    {
        syslog(LOG_ERR, "malloc():%s", strerror(errno));
        return NULL;
    }

    me->tbf = mytbf_init(MP3_BITRATE/8, MP3_BITRATE/8*5);
    syslog(LOG_WARNING,"mytbf has inited");
    if(me->tbf == NULL)
    {
        syslog(LOG_ERR, "mytbf_init():%s", strerror(errno));
        free(me);
        return NULL;
    }
    me->desc = strdup(linebuf);
    strncpy(pathstr, path, MAX_PATH);
    strncat(pathstr, "/*.mp3", MAX_PATH);
    if(glob(pathstr, 0, NULL, &me->mp3glob) != 0)
    {
        curr_id++;
        syslog(LOG_ERR, "%s is not a channel dir(can not find mp3 files", path);
        free(me);
        return NULL;
    }
    me->pos = 0;
    me->offset = 0;
    me->fd = open(me->mp3glob.gl_pathv[me->pos], O_RDONLY);
    if(me->fd <0 )
    {
        syslog(LOG_WARNING, "%s open failed.",me->mp3glob.gl_pathv[me->pos]);
        free(me);
        return NULL;
    }
    me->channid = curr_id;
    curr_id++;
    return me;
}



int media_getchannelList(media_entity_st** result,int *len){
   // 传入一个一级指针地址，将实际地址返回，且将长度返回，所以使用int指针
    // 返回值为是否成功 
    channel_context_st* res;  // 接收完整的信息，channel_context_st 
    media_entity_st* ptr_temp; // 将完整信息中的一部分接收过来
    for(int i=1;i<CHANNERNO;i++){
        channel_context[i].channid=-1;
    }   

    char path[MAX_PATH];
    glob_t globres;
    int entity_num=0;

    sprintf(path,"%s/*",server_cfg.mediaDir);

    if(glob(path,0,NULL,&globres)){  // 解析路径，特殊要求，出错路径，解析结果
        return -1 ; // 解析失败
    }

    ptr_temp = (media_entity_st*)malloc(sizeof(media_entity_st)*globres.gl_pathc);//new channel_context_st[globres.gl_pathc];

    if(ptr_temp==NULL){
        syslog(LOG_ERR,"new channel context failed");
    }

    for(int i=0;i<globres.gl_pathc;i++){
        res = path2entity(globres.gl_pathv[i]); // gl_pathv[i] 解析出来的就是 MyMedia/ch1 
        if(res){ // 当目录下没有desc文件的时候，返回NULL，不解析这个文件夹（频道信息）
            memcpy(channel_context+res->channid,res,sizeof(*res));
            ptr_temp[entity_num].desc = strdup(res->desc);
            ptr_temp[entity_num].channid = res->channid;
            entity_num++; 
            syslog(LOG_DEBUG,"in medialib entity num is %d",entity_num);
        }
    }

    //relloc 在原来的基础之上尝试增加内存空间，地址不变
    *result = (media_entity_st*)realloc(ptr_temp, sizeof(channel_context_st) * entity_num);
    if(*result == NULL)
    {
        syslog(LOG_ERR, "realloc() failed.");
        exit(1);
    }
    *len = entity_num;
    // syslog(LOG_DEBUG,"return in [ %s :  %d ]",__FILE__,__LINE__);
    return 0;
}
    


int media_freechannelList(media_entity_st* ptr){
    //因为创建的时候分配了内存，所以需要将内存释放
    free(ptr);
    return 0;
}
    

static int open_next(channid_t channid){
    for(int i=0;i<channel_context[channid].mp3glob.gl_pathc;i++){
        channel_context[channid].pos++;
        if(channel_context[channid].pos==channel_context[channid].mp3glob.gl_pathc){
            //如果pos到达了最大值
            channel_context[channid].pos=0; // 从头再来一次，将pos置为0
            // return -1;
            break;

        }
        close(channel_context[channid].fd);
        channel_context[channid].fd = open(channel_context[channid].mp3glob.gl_pathv[channel_context[channid].pos],O_RDONLY);
        if(channel_context[channid].fd<0){
            syslog(LOG_WARNING,"open failed in open next");
        } 
        else{//成功
            channel_context[channid].offset=0;
        }
    }
    // syslog(LOG_ERR,"channel id %d open failed",channid);
}


int media_readChannel(channid_t channid,void *dest,size_t size){
    // 从什么频道读，读到哪里，读多少长度
    //返回实际读到的长度
    int tbfsize = 0;
    tbfsize = mytbf_gettoken(channel_context[channid].tbf,size);
    // syslog(LOG_DEBUG,"read channel [ %s : %d ]",__FILE__,__LINE__);
    int len=0;
    char buff[102400];
    while (1)
    {
         
        // syslog(LOG_DEBUG,"before pread  [ %s : %d ]",__FILE__,__LINE__);
        // syslog(LOG_DEBUG,"channid : %d, fd : %d, tbfsize: %d, offset: %d ",channid,channel_context[channid].fd,tbfsize,channel_context[channid].offset);
        len = pread(channel_context[channid].fd,buff,tbfsize,channel_context[channid].offset); // 在多线程中，防止另一个线程修改lseek，即修改文件偏移量
        // syslog(LOG_DEBUG,"pread success [ %s : %d ]",__FILE__,__LINE__);
        
        if(len<0){
            syslog(LOG_WARNING,"this music cnnot read");
            open_next(channid);
            
        }
        else if (len==0){
            syslog(LOG_DEBUG,"this music has end in file %s : %d",__FILE__,__LINE__);
            open_next(channid);
        }else{
            channel_context[channid].offset+=len;
            // return size;
            break;
        }
        // 从一个fd读 tbfsize 个字节到buff中去，从offset偏移量位置处开始读
        
    }
    if(tbfsize-len>0){
        mytbf_returntoken(channel_context[channid].tbf,tbfsize-len);
    }
    return len;
}
    